Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Ещё раз про классы, надеюсь последний:) (Advanced Guest)
Author Message
Advanced Guest
Guest





Карма: 388
   поощрить/наказать


PostPosted: Mon Sep 15, 2008 2:14 am (написано за 9 минут 14 секунд)
   Post subject: Ещё раз про классы, надеюсь последний:)
Reply with quote

Задавал этот вопрос ранее, думал мне всё объяснили, но блин опять прихожу к мысли о том, что "что-то тут не так".

У меня есть класс работы с кэшем, класс работы с бд.
Используются они где попало.
Пробую пока 2 одновременно способа использования
класс бд статический и пишу везде classBD:functioncall([optional $connect]);
класс работы с кэшем динамический и приходится протаскивать всюду или в глобальных массив с возможными именами экземпляров

Я ИСКРЕННЕ скучаю по тому времени, когда работал с функциями и мог просто написать

dbquery($sql); или dbquery($sql,$connectid);
сейчас мне приходится коверкая пальцы (кто придумал эту дурную конструкцию с :: ?) писать
classBD::dbquery($sql); или classBD::dbquery($sql,$connectid);

с кэшем еще хуже, мне к тому же всюду приходится протаскивать глобальный массив для обращения к нему
плюс пальцы на конструкциях вида $cache[1]->saveCache($data); коверкаются куда сильнее чем на прежних
saveCache($data) или saveCache($data,$GLOBALS['cache'][1]);

Неужели мои мучения это именно отражение идеологии ООП?
Нет, так то мне классы нравятся, достаточно удобно все завернулось и для работы с БД и для работы с кэшем... но вот использование...
доходит уже до того, что я пишу обертку в виде функций над классом вида
function dbquery/filecashe($sql,$connectid=false) {
global $bd,$cache; static $connect;
//тут уже непосредственно вызов класса и ОДИН раз указание нужных глобальынх
classBD:dbquery($sql,$connect);
$cache[1]->saveCache($sql);
}
только для того, что бы не коверкать пальцы и не таскать для каждого вызова функции класса в глобальных (или синглтонах) его экземпляр
Back to top
dimagolov
Участник форума



Joined: 04 Feb 2007
Posts: 1664
Карма: 96
   поощрить/наказать

Location: Christ Church, Barbados

PostPosted: Mon Sep 15, 2008 2:19 am (спустя 5 минут; написано за 50 секунд)
   Post subject:
Reply with quote

ООП придумывали не для того, чотбы сократить кол-во нажатий на клавиши программистами, а для удобства разработки и поддержки.
Back to top
View user's profile Send private message
Advanced Guest
Guest





Карма: 388
   поощрить/наказать


PostPosted: Mon Sep 15, 2008 4:13 am (спустя 1 час 53 минуты; написано за 2 минуты 44 секунды)
   Post subject:
Reply with quote

ООП придумывали не для того, чотбы сократить кол-во нажатий на клавиши программистами, а для удобства разработки и поддержки.
---
Я вижу удобство разработки когда я могу просто вызвать функцию, не передавая ей избыточные аргументы таким образом
query($sql);
не таская за собой непонятным образом в глобальных (или вытаскивая из синглтона) имя экземпляра класса
$db->squery($sql);
или указывая каждый раз имя класса отдельно, привязываясь к нему
classBD::query($sql);
Back to top
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 83
   поощрить/наказать


PostPosted: Mon Sep 15, 2008 11:46 am (спустя 7 часов 33 минуты; написано за 41 секунду)
   Post subject:
Reply with quote

Advanced Guest,
а так...
Code (php): скопировать код в буфер обмена
function query($sql)
{
    call_user_func (www.php.net/call_user_func)(array (www.php.net/array)('classBD', 'query'), $sql);
}
Back to top
View user's profile Send private message Send e-mail
Advanced Guest
Guest





Карма: 388
   поощрить/наказать


PostPosted: Mon Sep 15, 2008 2:01 pm (спустя 2 часа 15 минут; написано за 37 секунд)
   Post subject:
Reply with quote

Александр Михалицын,
Вот так и приходится сейчас обёртывать, я же написал в первом сообщении.
Но это жуткий изврат, использовать функции для обертки объектов...
Back to top
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 83
   поощрить/наказать


PostPosted: Mon Sep 15, 2008 2:14 pm (спустя 13 минут; написано за 11 секунд)
   Post subject:
Reply with quote

Advanced Guest,
боюсь другого способа нет.
Back to top
View user's profile Send private message Send e-mail
Антон Макаренко
Участник форума



Joined: 05 Feb 2004
Posts: 374
Карма: 37
   поощрить/наказать

Location: Киев

PostPosted: Tue Sep 16, 2008 12:36 am (спустя 10 часов 21 минуту; написано за 6 минут 44 секунды)
   Post subject:
Reply with quote

Городить огород с классами приходится тогда, когда не хватает возможностей функций.
Возьмем к примеру Zend_Cache - почитайте документацию, оцените для себя удобство использования таких конструкций, как
Code (php): скопировать код в буфер обмена
$cache = Zend_Cache::factory($frontendName, $backendName, $frontendOptions, $backendOptions);
// ...
Zend_Cache::get();
или
Code (php): скопировать код в буфер обмена
<?php
//

$id = 'myBigLoop'; //

if (!($data = $cache->load($id))) {
    //

    $data = '';
    for ($i = 0; $i < 10000; $i++) {
        $data = $data . $i;
    }

    $cache->save($data);

}

//
 
(все взято из мануала)

Наследование, перегрузка методов и атрибутов - вот где кроется удобство ООП. Инкапсуляция, интерфейсы - это основа надежного ООП-кода. В функциях этого нет. В глобальных переменных мы получим как раз обратное - ненадежность, уязвимость в корне.
Back to top
View user's profile Send private message Send e-mail
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 268
   поощрить/наказать

Location: Питер

PostPosted: Tue Sep 16, 2008 10:08 am (спустя 9 часов 31 минуту; написано за 9 минут 44 секунды)
   Post subject:
Reply with quote

Advanced Guest
Тут присутствует целый сонм недоработок в архитектуре, повлёкший сии проблемы...

1) таскать массив кешей никуда не нужно, должен быть один-единственный класс для управления им. Например, некий статический/синглтоновый dataCache, который будет управлять всеми кешируемыми объектами. Можете посмотреть forum.dklab.ru/comments/lib/Dklab_cachePravilnoeKeshirovanieTegiVMemcachedNamespacesStatistika.html.
2) если не хочется привязываться к конкретному имени статического класса, можно использовать, например, такой подход
Code (any language): скопировать код в буфер обмена
classResolver::get(classResolver::CLASS_DATABASE)->query();
classResolver::get(classResolver::CLASS_CACHE)->invalidate();
3) Ну и вообще, с ООП возникают очень большие проблемы при выполнении следующих условий:
 а) хочется использовать все паттерны/подходы/новинки в одном месте и сразу - каша она и есть каша, расхлёбывать то ещё удовольствие. Например, дело доходит до появления классов вида DoubleProxyClass.
 б) начало программирования без чёткой архитектуры приложения - как раз текущий случай, когда не прописана процедура работы с кешем, доступа к БД и т.п.
 в) чрезмерное увлечение смесью функционального и ООП подходов - подход обёртывания обращения к классу в функцию несостоятелен, именно в силу ограничений функциональной модели разработки, поскольку крайне ограничивает пространство для манёвров и вводит кучу откровенно мусорного кода.
Back to top
View user's profile Send private message
Advanced Guest
Guest





Карма: 388
   поощрить/наказать


PostPosted: Tue Sep 16, 2008 9:25 pm (спустя 11 часов 16 минут; написано за 4 минуты 22 секунды)
   Post subject:
Reply with quote

Антон Макаренко, Ваш пример я честно говоря не понял к чему. Уточните пожалуйста что он должен был показать.

WingedFox,
1) Дык не важно что таскать. singletone::getOurId(); или global $ourid - один фиг лишняя строчка, которую надо не забывать написать. А в случае функций можно забыть.
2) Ужас:(
3а) Ага. Тут Вы правы абсолютно, на это и напоролся.
3б) Как раз архитектура есть, но вот если с функциями доступ к нужным фунциям (извините за тавтологию) реализовывался отлично, то с ооп приходится городить огород с протягиванием или нужных экземпляров, или названиями классов или еще чем-нибудь. Просто где-то надо исопльзовать кэш, где-то нет, где-то используется частично второе предложение и кэш уже активирован.
3в) Тут даже не знаю что сказать. С одной стороны согласен, с другой стороны обертка в функции позволяет избавиться от протаскивания избыточных данных.
Back to top
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 268
   поощрить/наказать

Location: Питер

PostPosted: Wed Sep 17, 2008 8:32 am (спустя 11 часов 7 минут; написано за 42 минуты 45 секунд)
   Post subject:
Reply with quote

Advanced Guest
Как раз, это важно - что именно таскать. Глобальную переменную можно даже случайно переписать, и получить совершенно непредсказуемый результат.
А при хорошем дизайне приложения только базовые классы будут знать о всяких синглтонах, ну и наследники - если уж очень припечёт.

Как пример, есть такая штука как ORM (en.wikipedia.org/wiki/Object-relational_mapping) - там об SQL, да и вообще о запросах к базе никто не задумывается (если только не нужны максимальные оптимизации). Ровно по той же схеме можно идти при разработке своего приложения.
1) Единственный класс для работы с базой данных (модель)
2) На него завязаны классы сущностей. Наследники сущностей только правят (тем или иным образом) SQL запрос базового класса (модель)
3) Классы операций, которые умеют работать с определёнными методами сущностей, но ни коим образом явно не влияют на генерируемый запрос (контроллер)
4) Классы управления UI, которые умеют (представление)
  а) получить от класса операций нужную сущность
  б) вынуть из сущности нужные данные (здесь модель и представление связаны наиболее сильно)

На всякий случай - это набросок "на пальцах", не претендующий ни на полноту, ни на истинность. Тем более - это не есть руководство к проектированию =)

В результате использования подобного подхода снимается завязка на внешние ключи (некий singleton::getId()), поскольку любая сущность представляет собой самодостаточный объект, содержащий всю необходимую информацию, чтобы управлять самим собой.

Ровно та же ситуация складывается и с кешем - работа с ним реализуется на разных уровнях:
1) поверх БД, на уровне "запрос-ответ"
2) при использовании шаблона "proxy, (заместитель) (ru.wikipedia.org/wiki/Proxy_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F))", на уровне объектных данных
3) на уровне работы с пользовательскими данными (например с данными сессии)
и так далее.

В таком случае, связанность с конкретными базовыми классами будет минимальной, если не делать попытки скрестить ежа с ужом... Проще изначально вывести "ежоужа" и от него наследоваться.
Advanced Guest wrote:
то с ооп приходится городить огород с протягиванием или нужных экземпляров, или названиями классов или еще чем-нибудь.
Вот это и называется - отсутствие архитектуры =)
По большому счёту, количество одновременно существующих сущностей не так уж и велико, если к этому стремиться. И в большинстве случаев совсем не требуется на каждом этапе знать "а кто же я есть?".
Например, есть сущность "список объектов в каталоге", читающая данные из БД.
Code (any language): скопировать код в буфер обмена
class ObjectList extends DatabaseList {
    protected OrmQuery getQuery() {
        // тут строится запрос из предикатов некой ОRM
        // например, return new OrmQuery().append(new OrmSelect('*')).append(new OrmFrom('objectlist'))
        // или return new OrmParsedQuery('select * from objectlist')
    }
}

class FilteredObjectList extends ObjectList {
    protected OrmQuery getQuery() {
        OrmQuery query = parent::getQuery();
        query.append(new OrmWhere("and name <> ''"));
        return query;
    }
}
Advanced Guest wrote:
Просто где-то надо исопльзовать кэш, где-то нет, где-то используется частично второе предложение и кэш уже активирован.
Ну так необходимость в кеше это не прихоть, а вполне конкретное свойство вполне конкретного объекта, который отвечает сам за себя. Если он умеет быть кешируемым, то отрезать такую возможность у наследников - нет смысла. Если не умеет - ну так и нечего её прикручивать снаружи. Она должна быть реализована "изнутри", исходя из логики работы самого объекта.

По большому счёту, "кеширование" для объекта - это операция сериализации его внутреннего состояния, с последующим восстановлением сущности. Можно написать "общий план сериализации", который будет учитывать некий набор объектов в системе, но этот план не будет гибким... В результате получится либо забивание кеша мусорными данными, либо - невозможность корректно сериализовать некие вновь добавленные объекты.
Таким образом, если нужно кешировать что-либо на уровне объектной модели, то потребуется ввести механизм сериализации объекта, который сможет
а) корректно собрать нужные данные
б) корректно собрать себя из результатов сериализации
Опять же, мы возвращаемся только ко внутренним механизмам объекта. Вообще, почитайте более объёмную статью про сериализацию (en.wikipedia.org/wiki/Serialization) =)
Advanced Guest wrote:
WingedFox wrote:
2) если не хочется привязываться к конкретному имени статического класса, можно использовать, например, такой подход
Code (any language): скопировать код в буфер обмена
classResolver::get(classResolver::CLASS_DATABASE)->query();
classResolver::get(classResolver::CLASS_CACHE)->invalidate();
2) Ужас:(
Не такой уж и "ужас". Подобный подход сводит в одно место все завязки на конкретные классы. Код, конечно, несколько монстрообразен.... Но - если он используется только в базовых классах, то почему бы и нет?
Другое дело что явные имена классов ничем не плохи. Просто потому, что желание сменить какой-либо слой в процессе работы над проектом возникает только при изменении мажорной цифры в номере релиза. А это ведёт к полному циклу тестирования приложения, так что глобальная замена по коду одного имени на другое ничего сильно не испортит. Ну, максимум - упадут несколько раз автоматические тесты =)
Advanced Guest wrote:
3в) Тут даже не знаю что сказать. С одной стороны согласен, с другой стороны обертка в функции позволяет избавиться от протаскивания избыточных данных.
Это миф. На самом деле - сие есть подпорка, причём не самого лучшего качества..... Просто потому, что при нормальном дизайне приложения не требуется ничего никуда "протаскивать". Тем более - избыточные данные.
Back to top
View user's profile Send private message
Advanced Guest
Guest





Карма: 388
   поощрить/наказать


PostPosted: Wed Sep 17, 2008 3:09 pm (спустя 6 часов 36 минут; написано за 22 секунды)
   Post subject:
Reply with quote

Прочитал, спасибо.
Ушел думать и вникать.
я еще вернусь:)
Back to top
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML